#include "NetConsole.h"

using namespace std;

NetConsole::NetConsole()
{
	isServer = false;
	prompt = true;
	peer = RakNetworkFactory::GetRakPeerInterface();
}

NetConsole::~NetConsole()
{
	RakNetworkFactory::DestroyRakPeerInterface(peer);
}

void __cdecl NetConsole::PrintMessage(RPCParameters *rpcParameters)
{
	sprintf(rpc, "%s\n", rpcParameters->input);
	
	output += string(rpc);

	if (isServer){
		peer->RPC(CLASS_MEMBER_ID(NetConsole,PrintMessage),(const char*)rpcParameters->input, rpcParameters->numberOfBitsOfData, HIGH_PRIORITY, RELIABLE_ORDERED, 0, rpcParameters->sender, true, 0, this->GetNetworkID(), 0);
	}
}

bool NetConsole::createServer(string &addr) {	

	peer->Startup(MAX_CLIENTS, 30, &SocketDescriptor(SERVER_PORT,0), 1);
	isServer = true;

	output += ("Starting the server.\n");
	// We need to let the server accept incoming connections from the clients
	peer->SetMaximumIncomingConnections(MAX_CLIENTS);
	address = string(peer->GetLocalIP(0));

	REGISTER_CLASS_MEMBER_RPC(peer, NetConsole, PrintMessage);

	serverNetworkIDManager.SetIsNetworkIDAuthority(true);
	peer->SetNetworkIDManager(&serverNetworkIDManager);

	this->SetNetworkIDManager(&serverNetworkIDManager);

	return true;
}


bool NetConsole::connectTo(const string & addr) {
	
	peer->Startup(1,30,&SocketDescriptor(), 1);
	isServer = false;

	output+=("Enter server IP or none for 127.0.0.1\n");
	if (address.size()==0){
		address = "127.0.0.1";
	} else {
		address = addr;
	}
	
	output+=("Starting the client.\n");
	peer->Connect(address.c_str(), SERVER_PORT, 0,0);
	
	REGISTER_CLASS_MEMBER_RPC(peer, NetConsole, PrintMessage);


	clientNetworkIDManager.SetIsNetworkIDAuthority(false);
	peer->SetNetworkIDManager(&clientNetworkIDManager);

	this->SetNetworkIDManager(&clientNetworkIDManager);

	return true;
}

bool NetConsole::update() {
	output.clear();

	if (!isServer){
		if (prompt) {
			output += ("Enter a string to show on the server: \n");
			prompt = false;
		}
		// Two tricky things here.  First, you have to remember to send the NULL terminator so you need strlen(str)+1
		// Second, if you didn't read the docs you might not realize RPC takes the number of bits rather than the number of bytes.
		// You have to multiply the number of bytes by 8
		// Don't forget that RPC takes bits as the data length, not bytes!
		if (!msg.empty()) {
			//client ran successfully
			peer->RPC(CLASS_MEMBER_ID(NetConsole,PrintMessage), msg.c_str(), (strlen(msg.c_str()) + 1)*8, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, this->GetNetworkID(),0);
			prompt = true;
		}
	}

	msg.clear();
	
	packet=peer->Receive();

	while(packet)
	{
		RakNet::BitStream bs;
		NetworkID appleNetworkID;

		switch (packet->data[0])
		{
		case ID_REMOTE_DISCONNECTION_NOTIFICATION:
			output += ("Another client has disconnected.\n");
			break;
		case ID_REMOTE_CONNECTION_LOST:
			output += ("Another client has lost the connection.\n");
			break;
		case ID_REMOTE_NEW_INCOMING_CONNECTION:
			output += ("Another client has connected.\n");
			break;
		case ID_CONNECTION_REQUEST_ACCEPTED:
			output += ("Our connection request has been accepted.\n");
			//printf("Enter a string to show on the server: ");
			//gets(str);
			// Two tricky things here.  First, you have to remember to send the NULL terminator so you need strlen(str)+1
			// Second, if you didn't read the docs you might not realize RPC takes the number of bits rather than the number of bytes.
			// You have to multiply the number of bytes by 8
			// Don't forget that RPC takes bits as the data length, not bytes!
			//peer->RPC("PrintMessage",str, (strlen(str)+1)*8, HIGH_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0);
			break;

		case ID_NEW_INCOMING_CONNECTION:
			output += ("A connection is incoming.\n");
			bs.Write(unsigned char(ID_USER_SERVERAPPLE_CREATED));
			bs.Write(this->GetNetworkID());
			peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
			break;
		case ID_NO_FREE_INCOMING_CONNECTIONS:
			output += ("The server is full.\n");
			break;
		case ID_DISCONNECTION_NOTIFICATION:
			if (isServer){
				output += ("A client has disconnected.\n");
			} else {
				output += ("We have been disconnected.\n");
			}
			break;
		case ID_CONNECTION_LOST:
			if (isServer){
				output += ("A client lost the connection.\n");
			} else {
				output += ("Connection lost.\n");
			}
			break;
		case ID_USER_SERVERAPPLE_CREATED:
			bs = RakNet::BitStream(packet->data, packet->length, false);
			// Ignore the message ID
			bs.IgnoreBits(8);

			bs.Read(appleNetworkID);
			this->SetNetworkIDManager(&clientNetworkIDManager);
			this->SetNetworkID(appleNetworkID);

			break;
		default:
			output += ("Message with identifier %i has arrived.\n", packet->data[0]);
			break;
		}

		peer->DeallocatePacket(packet);

		// Stay in the loop as long as there are more packets.
		packet = peer->Receive();
	}

	return true;
}